package parser

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/gohcl"
	"github.com/hashicorp/hcl/v2/hclsyntax"
	"github.com/ihaiker/tfwrapper/internal/config"
	"github.com/ihaiker/tfwrapper/internal/errors"
	"github.com/ihaiker/tfwrapper/internal/eval"
	"github.com/ihaiker/tfwrapper/internal/logger"
)

func parseFunctions(options config.Running, file *hcl.File) ([]config.Function, hcl.Diagnostics) {
	log := logger.Logger(options)

	content, _, diags := file.Body.PartialContent(&hcl.BodySchema{
		Blocks: []hcl.BlockHeaderSchema{
			{Type: "function", LabelNames: []string{"name"}},
		},
	})
	if diags.HasErrors() {
		return nil, diags
	}
	if len(content.Blocks) == 0 {
		return nil, diags
	}

	ctx, diags := eval.CreateEvalContext(options)
	if diags.HasErrors() {
		return nil, diags
	}

	functions := make([]config.Function, len(content.Blocks))
	for idx := 0; idx < len(functions); idx++ {
		fn := config.Function{}
		body := content.Blocks[idx].Body
		diags = gohcl.DecodeBody(body, ctx.EvalContext, &fn)
		if diags.HasErrors() {
			return nil, diags
		}
		if diags = parseFunctionBody(&fn); diags.HasErrors() {
			return nil, diags
		}
		fn.Name = content.Blocks[idx].Labels[0]
		functions[idx] = fn
	}

	for _, f := range functions {
		log.Debugf("found defined function %s", color.HiMagentaString(f.Name))
	}

	return functions, diags
}

func parseFunctionBody(fn *config.Function) hcl.Diagnostics {
	ct, _, diags := fn.Body.PartialContent(&hcl.BodySchema{
		Attributes: []hcl.AttributeSchema{
			{Name: "command", Required: true},
			{Name: "working_dir", Required: false},
			{Name: "args", Required: false},
		},
		Blocks: []hcl.BlockHeaderSchema{
			{Type: "env"},
		},
	})
	if diags.HasErrors() {
		return diags
	}
	fn.Command = ct.Attributes["command"]
	if fn.Command == nil {
		return errors.Diagnostics("Command not found",
			fmt.Errorf("the function named %s command not found", fn.Name))
	}
	fn.WorkingDir = ct.Attributes["working_dir"]
	fn.Args = ct.Attributes["args"]

	fn.Env = make(map[string]*hcl.Attribute)
	if len(ct.Blocks) > 0 {
		for name, attribute := range ct.Blocks[0].Body.(*hclsyntax.Body).Attributes {
			fn.Env[name] = attribute.AsHCLAttribute()
		}
	}
	return diags
}
